package com.dj.ms.configure;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.dj.common.constants.FeignCliConstants;
import com.dj.common.support.mvc.QueryRequestBodyMethodProcessor;
import com.dj.ms.configure.props.SpringWebMvcProps;
import com.dj.ms.interceptor.AuthenticationInterceptor;
import com.dj.ms.interceptor.PrometheusInterceptor;
import com.dj.ms.resolver.CurrentUserMethodResolver;
import com.dj.ms.resolver.WebExceptionResolver;
import com.dj.ms.support.feign.FeignAPIController;
import com.dj.ms.support.feign.FeignApiPathProperties;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.util.ResourceUtils;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;
import java.util.List;

/**
 * <br>
 * <p>mvc cfg</p>
 *
 * <br>
 *
 * @author ZJG
 * @version 1.0
 * @date 2021/8/13 下午2:06
 */
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE - 100)
@Configuration
@EnableConfigurationProperties(SpringWebMvcProps.class)
@ComponentScan(basePackages = "com.dj.ms.controller")
public class SpringWebMvcConfigurer implements WebMvcConfigurer {

    @Autowired
    private SpringWebMvcProps springWebMvcProps;

    @Resource
    private FeignApiPathProperties feignApiPathProperties;


    @Value("${spring.profiles.active}")
    private String activeProfiles;


    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**")
                .addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX + "/static/");
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        String prefix = ObjectUtil.isNotNull(feignApiPathProperties)?
                feignApiPathProperties.getBasePath():
                FeignCliConstants.PREFIX;
        configurer.addPathPrefix(prefix,  c -> c.isAnnotationPresent(FeignAPIController.class));
    }

    private static final String[] excludePatterns = new String[]{
            "/favicon.ico",
            "feign-provider",
            "/feign-provider",
            "/feign-provider/**",
            "/swagger-resources/**",
            "/webjars/**",
            "/v3/**",
            "/v3/api-docs/**",
            "/swagger-ui.html/**",
            "/swagger-ui",
            "/swagger-ui/**",
            "/swagger-resources",
            "/swagger-resources/",
            "/swagger-resources/**",
            "/doc.html",
            "/doc.html/**",
            "/doc.html#/**",
            "/doc",
            "/doc/**",
            "/docs",
            "/docs/**",
            "/api",
            "/api/**",
            "/api-docs",
            "/api-docs/**",
            "/init",
            "/list",
            "/list/**",
            "/welcome",
            "/welcome/**",
            "/user",
            "/user/**",
            "/console",
            "/console/**",
            "/common/health",
            "/metrics",
            "/metrics/",
            "/metrics/**",
            "/actuator",
            "/actuator/",
            "/actuator/**",
            "/actuator/prometheus/",
            "/actuator/prometheus/**",
            "/actuator/health/",
            "/actuator/health/**",
            "/actuator/health/readiness",
            "/actuator/health/liveness"
    };

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        List<String> excludePaths = Lists.newArrayList();
        if (StrUtil.isNotBlank(springWebMvcProps.getExcludePathPatterns())) {
            excludePaths = CollectionUtil.toList(springWebMvcProps.getExcludePathPatterns().split(","));
        }
        String[] exclude = excludePatterns;
        if (CollectionUtil.isNotEmpty(excludePaths)) {
            String[] exs = excludePaths.toArray(new String[]{});
            if (ObjectUtil.isNotNull(exs) && exs.length > 0) {
                exclude = ArrayUtil.addAll(exs, excludePatterns);
            }
        }

        //鉴权intercept
        registry.addInterceptor(new AuthenticationInterceptor(activeProfiles))
                .addPathPatterns("/**")
                .excludePathPatterns(exclude);

        //监控intercept
        registry.addInterceptor(new PrometheusInterceptor())
                .addPathPatterns("/**");
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new CurrentUserMethodResolver());
    }

    @Override
    public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        resolvers.add(new WebExceptionResolver());
    }



}